home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Prog / U-Z / VideoToolBox Folder / VideoToolboxSources / SetPixelsQuickly.c < prev    next >
Encoding:
Text File  |  1993-02-23  |  16.1 KB  |  530 lines  |  [TEXT/KAHL]

  1. /*
  2. SetPixelsQuickly.c
  3. All the Set... routines poke a row of pixels.
  4. All the Get... routines peek a row of pixels.
  5. SetPixelsQuickly and GetPixelsQuickly use the current port.
  6. SetWindowPixelsQuickly and GetWindowPixelsQuickly use the supplied window.
  7. SetDevicePixelsQuickly and GetDevicePixelsQuickly use the supplied video device.
  8. SetPixmapPixelsQuickly and GetPixmapPixelsQuickly use the supplied pix/bitmap.
  9.  
  10. int SetPixelsQuickly(int x,int y,unsigned long value[],short n);
  11. int GetPixelsQuickly(int x,int y,unsigned long value[],short n);
  12. int SetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long value[],short n);
  13. int GetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long value[],short n);
  14. int SetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n);
  15. int GetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n);
  16. int SetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[],short n);
  17. int GetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[],short n);
  18.  
  19. This is the fastest and easiest way to transform back and forth between a PixMap
  20. or BitMap and a numerical representation of an arbitrary image amenable to
  21. computation in C. You can think of these routines as replacements for the
  22. official Apple SetCPixel, etc. Their virtue is that they're very fast and don't
  23. translate your index via any color table. Set... and Get... ignore the color
  24. spec arrays, giving you direct access to the unsigned number stored in each
  25. pixel (whether 1, 2, 4, 8, 16, or 32 bits). With appropriate casting you may
  26. supply a CWindowPtr in place of the WindowPtr, and you may supply a BitMapPtr in
  27. place of the PixMapPtr.
  28.  
  29. For all the routines, you supply the (x,y) coordinate of the first pixel you
  30. want to access in the appropriate coordinate system, an unsigned long array
  31. called "value", and the number of pixels to access. x will increment for each
  32. successive pixel. Set... will copy values, one by one, from "value" into the
  33. pix/bitmap. Get... will copy from the pix/bitmap into "value". The routine work
  34. with all pixel sizes: 1 to 32 bits. The "value" array that you supply is always
  35. unsigned long.
  36.  
  37. All the routines clip to enforce either the pix/bitmap's bounds, or the window's
  38. portRect (if you pass a window or use the current window/port). The only way of
  39. getting into trouble would be to pass a window's PixMap directly. It is
  40. difficult to figure out the clipping of a window's PixMap; RectToAddress does
  41. it, but only on the first call, after which we use the old cached answer, which
  42. doesn't include clipping information.
  43.  
  44. The returned value of the function is normally zero, indicating success, but
  45. will be nonzero if the request could not be fully satisfied. All the routines
  46. clip to the bit/pixmap bounds; this is treated as normal by the Set... routines
  47. and is reported as an error by the Get... routines. In the latter case some of
  48. the elements of the value array will have been left untouched because the pixels
  49. they correspond to could not be accessed.
  50.  
  51. These routines (and RectToAddress) do not "move memory", i.e. they don't give
  52. the Memory Manager any pretext for shuffling around the memory allocations and
  53. change its master pointers. That's why it's OK to dereference the pixmap handle,
  54. passing as an argument a temporary copy of the pixmap's master pointer.
  55.  
  56. SetPixmapPixelsQuickly and GetPixmapPixelsQuickly run fast by caching the
  57. information that they get about your Bit/Pixmap from RectToAddress. Each has its
  58. own cache. The cache is assumed to be fresh (i.e. is not recomputed) if it
  59. receives the same Pix/Bitmap as last time. It checks whether the pix/bitmap has
  60. the same address, baseAddr, rowBytes, and bounds. You can force a flush of the
  61. cache by passing a NULL bit/pixmap pointer. (This will result in a returned
  62. value of 0, since the flush is always successful.)
  63.  
  64. See the demo Grating.c for an example of how to use this to display a pattern on
  65. the screen.
  66.  
  67.     // This is a simple write-then-read test of these routines,
  68.     // writing random numbers to the top line of the main screen.
  69.     unsigned long row[100],row2[100];
  70.     int rowLength=100,colors,i;
  71.     device=GetMainDevice();
  72.     colors=(**(**(**device).gdPMap).pmTable).ctSize+1;
  73.     for(i=0;i<rowLength;i++)row[i]=nrand(colors);
  74.     SetDevicePixelsQuickly(device,0,0,row,rowLength);
  75.     SetDevicePixelsQuickly(device,0,0,row2,rowLength);
  76.     for(i=0;i<rowLength;i++)if(row2[i]!=row[i])
  77.         printf("%d-th pixel: wrote %ld, but read %ld\n",i,row[i],row2[i]);
  78.  
  79. HISTORY:
  80. 4/4/89    dgp wrote SetIPixel.c
  81. 9/8/90    dgp updated to work with 32 bit QuickDraw, if present.
  82. 10/15/90 bf renamed to SetIPixelGW.c and modified for drawing to off screen pix maps.
  83. 4/26/92    dgp    Merged the two variants: SetIPixel.c and SetIPixelGW.c to produce the
  84.             new file SetOnePixel.c. Renamed existing routines to SetPixmapPixel,
  85.             GetPixmapPixel,SetDevicePixel,GetDevicePixel. Added SetOnePixel and 
  86.             GetOnePixel. Generalized to handle any pixelSize, and accept bitmaps as well
  87.             as pixmaps.
  88. 12/23/92 dgp Doubled the speed of SetPixmapPixel and GetPixmapPixel (and thus sped up
  89.             all the routines that call them) by caching the answers from RectToAddress. 
  90. 1/6/93 dgp    Fixed tiny but disastrous bug in GetPixmapPixel (wasn't saving old x and y).
  91. 1/22/93    dgp    Check more PixMap fields to make sure cache is not stale.
  92. 2/7/93    dgp Wrote SetPixelsQuickly.c
  93. 2/8/93    dgp Ironed out some wrinkles in the clipping.
  94. */
  95. #include "VideoToolbox.h"
  96. #define USE_CACHE 1    // set to zero to disable cache
  97.  
  98. int SetPixelsQuickly(int x,int y,unsigned long value[],short n)
  99. // (x,y) is in the local coordinate system of the current port.
  100. {
  101.     WindowPtr window;
  102.  
  103.     GetPort(&window);
  104.     return SetWindowPixelsQuickly(window,x,y,value,n);
  105. }
  106.  
  107. int GetPixelsQuickly(int x,int y,unsigned long value[],short n)
  108. // (x,y) is in the local coordinate system of the current port.
  109. {
  110.     WindowPtr window;
  111.  
  112.     GetPort(&window);
  113.     return GetWindowPixelsQuickly(window,x,y,value,n);
  114. }
  115.  
  116. int SetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long *value,short n)
  117. // (x,y) is in the local coordinate system of the window.
  118. // Accepts either WindowPtr or CWindowPtr.
  119. {
  120.     PixMapPtr pm;
  121.     Rect r;
  122.     
  123.     if(window==NULL)return 1;
  124.     
  125.     // Clip to portRect.
  126.     SetRect(&r,x,y,x+n,y+1);
  127.     if(!SectRect(&window->portRect,&r,&r))return 0;
  128.     value+=r.left-x;
  129.     x=r.left;
  130.     n=r.right-r.left;
  131.     
  132.     // Is it a CGrafPort or a GrafPort?
  133.     if(((CGrafPtr)window)->portVersion<0)        // It's a CGrafPort, pass pixmap ptr.
  134.         pm = *((CGrafPtr)window)->portPixMap;
  135.     else                                         // It's a GrafPort, pass bitmap ptr.
  136.         pm = (PixMapPtr) &window->portBits;
  137.     return SetPixmapPixelsQuickly(pm,x,y,value,n);
  138. }
  139.  
  140. int GetWindowPixelsQuickly(WindowPtr window,int x,int y,unsigned long *value,short n)
  141. // (x,y) is in the local coordinate system of the window.
  142. // Accepts WindowPtr or CWindowPtr.
  143. {
  144.     PixMapPtr pm;
  145.     int error=0;
  146.     Rect r;
  147.  
  148.     if(window==NULL)return 1;
  149.     
  150.     // Clip to portRect.
  151.     SetRect(&r,x,y,x+n,y+1);
  152.     if(!SectRect(&window->portRect,&r,&r))return 1;
  153.     if(x!=r.left || x+n!=r.right){    // Update after clipping.
  154.         error=1;
  155.         value+=r.left-x;
  156.         x=r.left;
  157.         n=r.right-r.left;
  158.     }
  159.     
  160.     // Is it a CGrafPort or a GrafPort?
  161.     if(((CGrafPtr)window)->portVersion<0)        // It's a CGrafPort, pass pixmap ptr.
  162.         pm = *((CGrafPtr)window)->portPixMap;
  163.     else                                         // It's a GrafPort, pass bitmap ptr.
  164.         pm = (PixMapPtr) &window->portBits;
  165.     error|=GetPixmapPixelsQuickly(pm,x,y,value,n);
  166.     return error;
  167. }
  168.  
  169. int SetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n)
  170. // (x,y) is relative to the upper left hand corner of the screen.
  171. {
  172.     Rect r;
  173.     
  174.     if(device==NULL)return 1;
  175.     x+=(*(*device)->gdPMap)->bounds.left;
  176.     y+=(*(*device)->gdPMap)->bounds.top;
  177.  
  178.     // Clip to device bounds.
  179.     SetRect(&r,x,y,x+n,y+1);
  180.     if(!SectRect(&(*(*device)->gdPMap)->bounds,&r,&r))return 0;
  181.     value+=r.left-x;    // Update after clipping.
  182.     x=r.left;
  183.     n=r.right-r.left;
  184.     
  185.     return SetPixmapPixelsQuickly(*(*device)->gdPMap,x,y,value,n);
  186. }
  187.  
  188. int GetDevicePixelsQuickly(GDHandle device,int x,int y,unsigned long value[],short n)
  189. // (x,y) is relative to the upper left hand corner of the screen.
  190. {
  191.     int error=1;
  192.     Rect r;
  193.     
  194.     if(device==NULL)return 1;
  195.     x+=(*(*device)->gdPMap)->bounds.left;
  196.     y+=(*(*device)->gdPMap)->bounds.top;
  197.     
  198.     // Clip to device bounds.
  199.     SetRect(&r,x,y,x+n,y+1);
  200.     if(!SectRect(&(*(*device)->gdPMap)->bounds,&r,&r))return 1;
  201.     if(x!=r.left || x+n!=r.right){    // Update after clipping.
  202.         error=1;
  203.         value+=r.left-x;
  204.         x=r.left;
  205.         n=r.right-r.left;
  206.     }
  207.     error|=GetPixmapPixelsQuickly(*(*device)->gdPMap,x,y,value,n);
  208.     return error;
  209. }
  210.  
  211. int SetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  212.     ,register short n)
  213. // Pokes a row of pixels. Accepts either pixmap or bitmap pointer.
  214. // (x,y) is in the coordinate system of the bit/pixmap.
  215. // Speed is enhanced by reusing the cached information from last time if it's the
  216. // same Pix/Bitmap as last time, i.e. same address, baseAddr,rowBytes, and bounds.
  217. // You can force it to flush its cache by passing a NULL bit/pixmap pointer.
  218. {
  219.     static PixMapPtr oldPmPtr=(PixMapPtr)-1;
  220.     static int oldX,oldY;
  221.     static short rowBytes,logPixelSize,bitsOffset;
  222.     static unsigned char *pixelPtr;
  223.     static BitMap oldMap;
  224.     static Ptr mainBaseAddr=NULL;
  225.     int shift,error=0;
  226.     unsigned char mask;
  227.     char mode32=true32b;
  228.     Rect r;
  229.     
  230.     // Clip to pix/bitmap bounds.
  231.     SetRect(&r,x,y,x+n,y+1);
  232.     if(mainBaseAddr==NULL){
  233.         if(QD8Exists())mainBaseAddr=(*(*GetMainDevice())->gdPMap)->baseAddr;
  234.         else mainBaseAddr=(void *)-1;
  235.     }
  236.     // Clip unless the pixmap pretends to be the main device.
  237.     if(pmPtr!=NULL && pmPtr->baseAddr!=mainBaseAddr 
  238.         && !SectRect(&pmPtr->bounds,&r,&r))return 0;    // go home if we're done
  239.  
  240.     if(!USE_CACHE || pmPtr!=oldPmPtr
  241.         || pmPtr->baseAddr!=oldMap.baseAddr 
  242.         || pmPtr->rowBytes!=oldMap.rowBytes 
  243.         || *(long *)&pmPtr->bounds.top!=*(long *)&oldMap.bounds.top
  244.         || *(long *)&pmPtr->bounds.bottom!=*(long *)&oldMap.bounds.bottom){
  245.         // Cache is stale. Get fresh values.
  246.         short pixelSize;
  247.         // RectToAddress computes pixelPtr and clips r to the bit/pixmap bounds.
  248.         pixelPtr=RectToAddress(pmPtr,&r,&rowBytes,&pixelSize,&bitsOffset);
  249.         if(pixelPtr==NULL){
  250.             oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  251.             return 0;
  252.         }
  253.         oldPmPtr=pmPtr;
  254.         oldMap=*(BitMap *)pmPtr;
  255.         logPixelSize=Log2L(pixelSize);
  256.         value+=r.left-x;    // Update after clipping.
  257.         x=r.left;
  258.         n=r.right-r.left;
  259.     }else{
  260.         // Cache is fresh. Merely correct for changes in x and y.
  261.         if(pixelPtr==NULL)return 1;
  262.         value+=r.left-x;    // Update after clipping.
  263.         x=r.left;
  264.         n=r.right-r.left;
  265.         if(x!=oldX){
  266.             if(logPixelSize<3){
  267.                 register long bits;
  268.                 bits=bitsOffset+(long)(x-oldX)<<logPixelSize;
  269.                 pixelPtr+=bits>>3;
  270.                 bitsOffset=bits&7;
  271.             }else pixelPtr+=(x-oldX)<<(logPixelSize-3);
  272.         }
  273.         if(y!=oldY)pixelPtr+=(long)(y-oldY)*rowBytes;
  274.     }
  275.     if(QD32Exists())SwapMMUMode(&mode32);
  276.     switch(logPixelSize){
  277.     case 0:{
  278.         register unsigned char val,mask,*ptr=pixelPtr;
  279.         shift=sizeof(*ptr)*8;
  280.         shift-=bitsOffset;    // from right, instead of from left
  281.         do{
  282.             val=mask=0;
  283.             do{
  284.                 shift-=1;
  285.                 val<<=1;
  286.                 mask<<=1;
  287.                 if(n>0){
  288.                     val|=(*value++)&1;
  289.                     mask|=1;
  290.                     n--;
  291.                 }else{
  292.                     val<<=shift;
  293.                     mask<<=shift;
  294.                     break;
  295.                 }
  296.             }while(shift>0);
  297.             mask=~mask;
  298.             *ptr= *ptr & mask | (unsigned char)val;
  299.             ptr++;
  300.             shift=sizeof(*ptr)*8;
  301.         }while(n>0);
  302.         break;
  303.     }
  304.     case 1:{
  305.         register unsigned char val,mask,*ptr=pixelPtr;
  306.         shift=sizeof(*ptr)*8;
  307.         shift-=bitsOffset;    // from right, instead of from left
  308.         do{
  309.             val=mask=0;
  310.             do{
  311.                 shift-=2;
  312.                 val<<=2;
  313.                 mask<<=2;
  314.                 if(n>0){
  315.                     val|=(*value++)&3;
  316.                     mask|=3;
  317.                     n--;
  318.                 }else{
  319.                     val<<=shift;
  320.                     mask<<=shift;
  321.                     break;
  322.                 }
  323.             }while(shift>0);
  324.             mask=~mask;
  325.             *ptr= *ptr & mask | (unsigned char)val;
  326.             ptr++;
  327.             shift=sizeof(*ptr)*8;
  328.         }while(n>0);
  329.         break;
  330.     }
  331.     case 2:{
  332.         register unsigned char val,mask,*ptr=pixelPtr;
  333.         shift=sizeof(*ptr)*8;
  334.         shift-=bitsOffset;    // from right, instead of from left
  335.         do{
  336.             val=mask=0;
  337.             do{
  338.                 shift-=4;
  339.                 val<<=4;
  340.                 mask<<=4;
  341.                 if(n>0){
  342.                     val|=(*value++)&15;
  343.                     mask|=15;
  344.                     n--;
  345.                 }else{
  346.                     val<<=shift;
  347.                     mask<<=shift;
  348.                     break;
  349.                 }
  350.             }while(shift>0);
  351.             mask=~mask;
  352.             *ptr= *ptr & mask | (unsigned char)val;
  353.             ptr++;
  354.             shift=sizeof(*ptr)*8;
  355.         }while(n>0);
  356.         break;
  357.     }
  358.     case 3:{
  359.         register unsigned char *pB=pixelPtr;
  360.         for(;n>0;n--) *pB++ = *value++;
  361.         break;
  362.     }
  363.     case 4:{
  364.         register unsigned short *pW=(unsigned short *)pixelPtr;
  365.         for(;n>0;n--) *pW++ = *value++;
  366.         break;
  367.     }
  368.     case 5:{
  369.         register unsigned long *pL=(unsigned long *)pixelPtr;
  370.         for(;n>0;n--) *pL++ = *value++;
  371.         break;
  372.     }
  373.     }
  374.     if(QD32Exists())SwapMMUMode(&mode32);
  375.     oldX=x;
  376.     oldY=y;
  377.     return error;
  378. }
  379.  
  380. int GetPixmapPixelsQuickly(PixMapPtr pmPtr,int x,int y,unsigned long value[]
  381.     ,register short n)
  382. // Peeks a rows of pixels of any size. Accepts either pixmap or bitmap pointer.
  383. // (x,y) is in the coordinate system of the bit/pixmap.
  384. // Speed is enhanced by reusing the cached information from last time if it's the
  385. // same Pix/Bitmap as last time, i.e. same address, baseAddr,rowBytes, and bounds.
  386. // You can force it to flush its cache by passing a NULL bit/pixmap pointer.
  387. {
  388.     static PixMapPtr oldPmPtr=(PixMapPtr)-1;
  389.     static int oldX,oldY;
  390.     static short rowBytes,logPixelSize,bitsOffset;
  391.     static unsigned char *pixelPtr;
  392.     static BitMap oldMap;
  393.     static Ptr mainBaseAddr=NULL;
  394.     int shift,error=0;
  395.     unsigned char mask;
  396.     char mode32=true32b;
  397.     Rect r;
  398.     
  399.     // Clip to pix/bitmap bounds.
  400.     SetRect(&r,x,y,x+n,y+1);
  401.     if(mainBaseAddr==NULL){
  402.         if(QD8Exists())mainBaseAddr=(*(*GetMainDevice())->gdPMap)->baseAddr;
  403.         else mainBaseAddr=(void *)-1;
  404.     }
  405.     // Clip unless the pixmap pretends to be the main device.
  406.     if(pmPtr!=NULL && pmPtr->baseAddr!=mainBaseAddr 
  407.         && !SectRect(&pmPtr->bounds,&r,&r))return 1;    // go home if we're done
  408.  
  409.     if(!USE_CACHE || pmPtr!=oldPmPtr
  410.         || pmPtr->baseAddr!=oldMap.baseAddr 
  411.         || pmPtr->rowBytes!=oldMap.rowBytes 
  412.         || *(long *)&pmPtr->bounds.top!=*(long *)&oldMap.bounds.top
  413.         || *(long *)&pmPtr->bounds.bottom!=*(long *)&oldMap.bounds.bottom){
  414.         // Cache is stale. Get fresh values.
  415.         short pixelSize;
  416.         // RectToAddress computes pixelPtr and clips r to the bit/pixmap bounds.
  417.         pixelPtr=RectToAddress(pmPtr,&r,&rowBytes,&pixelSize,&bitsOffset);
  418.         if(pixelPtr==NULL){
  419.             oldPmPtr=(PixMapPtr)-1;    // invalidate cache
  420.             return 0;
  421.         }
  422.         oldPmPtr=pmPtr;
  423.         oldMap=*(BitMap *)pmPtr;
  424.         logPixelSize=Log2L(pixelSize);
  425.         if(x!=r.left || x+n!=r.right){    // Update after clipping.
  426.             error=1;
  427.             value+=r.left-x;
  428.             x=r.left;
  429.             n=r.right-r.left;
  430.         }
  431.     }else{
  432.         // Cache is fresh. Merely correct for changes in x and y.
  433.         if(pixelPtr==NULL)return 1;
  434.         if(x!=r.left || x+n!=r.right){    // Update after clipping.
  435.             error=1;
  436.             value+=r.left-x;
  437.             x=r.left;
  438.             n=r.right-r.left;
  439.         }
  440.         if(x!=oldX){
  441.             if(logPixelSize<3){
  442.                 register long bits;
  443.                 bits=bitsOffset+(long)(x-oldX)<<logPixelSize;
  444.                 pixelPtr+=bits>>3;
  445.                 bitsOffset=bits&7;
  446.             }else pixelPtr+=(x-oldX)<<(logPixelSize-3);
  447.         }
  448.         if(y!=oldY)pixelPtr+=(long)(y-oldY)*rowBytes;
  449.     }
  450.     if(QD32Exists())SwapMMUMode(&mode32);
  451.     switch(logPixelSize){
  452.     case 0:{
  453.         register unsigned char val,*ptr=pixelPtr;
  454.         shift=sizeof(*ptr)*8;
  455.         shift-=bitsOffset;    // from right, instead of from left
  456.         do{
  457.             val=*ptr++;
  458.             do{
  459.                 shift-=1;
  460.                 if(n>0){
  461.                     *value++=(val>>shift)&1;
  462.                     n--;
  463.                 }else{
  464.                     break;
  465.                 }
  466.             }while(shift>0);
  467.             shift=sizeof(*ptr)*8;
  468.         }while(n>0);
  469.         break;
  470.     }
  471.     case 1:{
  472.         register unsigned char val,*ptr=pixelPtr;
  473.         shift=sizeof(*ptr)*8;
  474.         shift-=bitsOffset;    // from right, instead of from left
  475.         do{
  476.             val=*ptr++;
  477.             do{
  478.                 shift-=2;
  479.                 if(n>0){
  480.                     *value++=(val>>shift)&3;
  481.                     n--;
  482.                 }else{
  483.                     break;
  484.                 }
  485.             }while(shift>0);
  486.             shift=sizeof(*ptr)*8;
  487.         }while(n>0);
  488.         break;
  489.     }
  490.     case 2:{
  491.         register unsigned char val,*ptr=pixelPtr;
  492.         shift=sizeof(*ptr)*8;
  493.         shift-=bitsOffset;    // from right, instead of from left
  494.         do{
  495.             val=*ptr++;
  496.             do{
  497.                 shift-=4;
  498.                 if(n>0){
  499.                     *value++=(val>>shift)&15;
  500.                     n--;
  501.                 }else{
  502.                     break;
  503.                 }
  504.             }while(shift>0);
  505.             shift=sizeof(*ptr)*8;
  506.         }while(n>0);
  507.         break;
  508.     }
  509.     case 3:{
  510.         register unsigned char *pB=pixelPtr;
  511.         for(;n>0;n--) *value++=*pB++;
  512.         break;
  513.     }
  514.     case 4:{
  515.         register unsigned short *pW=(unsigned short *)pixelPtr;
  516.         for(;n>0;n--) *value++=*pW++;
  517.         break;
  518.     }
  519.     case 5:{
  520.         register unsigned long *pL=(unsigned long *)pixelPtr;
  521.         for(;n>0;n--) *value++=*pL++;
  522.         break;
  523.     }
  524.     }
  525.     if(QD32Exists())SwapMMUMode(&mode32);
  526.     oldX=x;
  527.     oldY=y;
  528.     return error;
  529. }
  530.